﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using System.Reflection;
using System.Collections.ObjectModel;
using System.Text.RegularExpressions;
using Mysoft.Map.Extensions.DAL;

namespace Mysoft.QuickCode.DbExpressionExtensions
{
    /// <summary>
    /// 此类作废（2015-3-12）
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <typeparam name="M"></typeparam>
    internal class JoinConditionBuilder<T, M> : ExpressionVisitor
        where T : class
        where M : class
    {
        /// <summary>
        /// 需要从参数中解析MemberExpression的解析方式
        /// </summary>
        string[] MemberInArgs = new string[] { "In", "Between", "NotEquals", "IsNull", "IsNotNull" };

        private List<object> m_arguments;
        private Stack<string> m_conditionParts;

        public string Condition { get; private set; }
        public object[] Arguments { get; set; }

        private EntityTable<T> _entityTable;
        private EntityTable<M> _joinEntityTable;

        /// <summary>
        /// 当前 VisitMethodCall 解释的方法表达式要生成的参数的个数，例如：Between需要生成2个参数才能完成格式化。
        /// </summary>
        private Stack<int> _callMethodParamterCount = new Stack<int>();

        /// <summary>
        /// entityTable对象的参数队列，用于暂存参数，最终会存入entityTable的参数栈中。
        /// </summary>
        private Queue<KeyValuePair<string, object>> _entityTableParamtersQueue = new Queue<KeyValuePair<string, object>>();

        public JoinConditionBuilder(EntityTable<T> entityTable, EntityTable<M> joinEntityTable)
        {
            this._entityTable = entityTable;
            this._joinEntityTable = joinEntityTable;
        }

        /// <summary>
        /// 构建SQL查询的Where语句
        /// </summary>
        /// <param name="expression"></param>
        public void Build(Expression expression)
        {
            PartialEvaluator evaluator = new PartialEvaluator();
            Expression evaluatedExpression = evaluator.Eval(expression);

            this.m_arguments = new List<object>();
            this.m_conditionParts = new Stack<string>();

            this.Visit(evaluatedExpression);

            this.Arguments = this.m_arguments.ToArray();
            this.Condition = this.m_conditionParts.Count > 0 ? this.m_conditionParts.Pop() : null;
        }

        #region 内部方法

        /// <summary>
        /// 添加格式化参数到参数数组中
        /// </summary>
        /// <param name="paramList">参数数组</param>
        /// <param name="paramValues">参数值</param>
        protected void AddParameter(ref List<object> paramList, object[] paramValues)
        {
            for (int i = 0; i < paramValues.Length; i++)
            {
                int index = this._entityTable.Parameters.Count + 1;   //参数索引
                string paramName = string.Format("p{0}", index);    //生成的参数名称
                paramList.Add(paramName);
                //添加参数到entityTable对象
                this._entityTable.Parameters.Push(new KeyValuePair<string, object>(paramName, paramValues[i]));
            }
        }

        #endregion

        protected override Expression VisitBinary(BinaryExpression b)
        {
            if (b == null)
            {
                return b;
            }
            string opr;
            switch (b.NodeType)
            {
                case ExpressionType.Equal:
                    opr = "=";
                    break;
                case ExpressionType.NotEqual:
                    opr = "<>";
                    break;
                case ExpressionType.GreaterThan:
                    opr = ">";
                    break;
                case ExpressionType.GreaterThanOrEqual:
                    opr = ">=";
                    break;
                case ExpressionType.LessThan:
                    opr = "<";
                    break;
                case ExpressionType.LessThanOrEqual:
                    opr = "<=";
                    break;
                case ExpressionType.AndAlso:
                    opr = "AND";
                    break;
                case ExpressionType.OrElse:
                    opr = "OR";
                    break;
                case ExpressionType.Add:
                    opr = "+";
                    break;
                case ExpressionType.Subtract:
                    opr = "-";
                    break;
                case ExpressionType.Multiply:
                    opr = "*";
                    break;
                case ExpressionType.Divide:
                    opr = "/";
                    break;
                default:
                    throw new NotSupportedException(b.NodeType + "不支持的NodeType");
            }

            this.Visit(b.Left);
            this.Visit(b.Right);

            string right = this.m_conditionParts.Pop();
            string left = this.m_conditionParts.Pop();

            string condition = String.Format("({0}) {1} ({2})", left, opr, right);
            this.m_conditionParts.Push(condition);

            return b;
        }

        /// <summary>
        /// 解析相关方法为SQL关键字
        /// </summary>
        /// <param name="m"></param>
        /// <returns></returns>
        protected override Expression VisitMethodCall(MethodCallExpression m)
        {
            if (m == null) { return m; }

            //格式化的参数列表
            List<object> paramList = new List<object>();
            //解析参数前，记录需要参数化的参数个数，用于后续 VisitMemberAccess 自动生成参数个数
            IEnumerable<Expression> args = this.VisitExpressionList(m.Arguments);

            //构建的条件语句
            string condition = string.Empty;
            string opr = string.Empty;
            switch (m.Method.Name)
            {
                case "Equals":
                    {
                        paramList.Add(this._entityTable.GetTableName() + "." + (this.Visit(m.Object) as MemberExpression).Member.Name); //T
                        paramList.Add(this._joinEntityTable.GetTableName() + "." + args.Select(v => (v as MemberExpression).Member.Name).FirstOrDefault()); //M
                        condition = string.Format("{0}={1}", paramList.ToArray());
                        break;
                    }
                case "ToString":
                    {
                        return m.Object;
                    }
                default:
                    {
                        throw new NotSupportedException(m.Method.Name + " 不支持");
                    }
            }

            this.m_conditionParts.Push(condition);

            return m;
        }

        protected override Expression VisitConstant(ConstantExpression c)
        {
            if (c == null || _entityTableParamtersQueue.Count == 0)
            {
                return c;
            }

            //更新参数化变量中参数对应的值
            KeyValuePair<string, object> kv = this._entityTableParamtersQueue.Dequeue(); //参数出队
            this._entityTable.Parameters.Push(new KeyValuePair<string, object>(kv.Key, c.Value)); //赋值后存入对象实entityTable参数栈中

            return c;
        }
    }
}
